package com.amarsoft.task.security.login;

import com.amarsoft.are.ARE;
import com.amarsoft.are.io.SystemConsole;
import com.amarsoft.are.security.DESEncrypt;
//import com.amarsoft.are.util.MD5;
import com.amarsoft.task.Task;
import com.amarsoft.task.security.LoginModule;
import com.amarsoft.task.security.TaskUser;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public abstract class AbstractAccountPasswordLogin implements LoginModule {
	private String accountPrompt;
	private String passwordPrompt;
	private String passwordAlgorithm;
	private int maxRetryTimes;
	private String account;
	private String password;
	private TaskUser tu;
	private AccountPasswordEnterWindow enterWindow;

	public AbstractAccountPasswordLogin() {
		this.accountPrompt = "Account";
		this.passwordPrompt = "Password";
		this.passwordAlgorithm = null;
		this.maxRetryTimes = 3;

		this.account = null;
		this.password = null;
		this.tu = null;
		this.enterWindow = null;
	}

	protected abstract TaskUser login(Task paramTask, String paramString1,
			String paramString2);

	public final TaskUser login(Task task) {
		int reryTimes = 0;
		while ((this.tu == null) && (reryTimes < getMaxRetryTimes())) {
			if (!(enterAccountAndPassword(task))) {
				ARE.getLog().debug("Login Canceled!");
				break;
			}
			this.tu = login(task, this.account, this.password);
			++reryTimes;
		}
		return this.tu;
	}

	private final boolean enterAccountAndPassword(Task task) {
		if ((task != null) && (task.getTaskWindow() != null)) {
			if (this.enterWindow == null) {
				this.enterWindow = new AccountPasswordEnterWindow(
						task.getTaskWindow());
				this.enterWindow.setAccountLabel(getAccountPrompt());
				this.enterWindow.setPasswordLabel(getPasswordPrompt());
			}
			this.enterWindow.setAccount(this.account);
			this.enterWindow.setPassword(this.password);
			if (this.enterWindow.enterAccountAndPassword()) {
				this.account = this.enterWindow.getAccount();
				this.password = this.enterWindow.getPassword();
				return true;
			}
			return false;
		}

		this.account = SystemConsole.readLine(getAccountPrompt() + ": ");
		char[] pw = SystemConsole.readPassword(getPasswordPrompt() + ": ");
		if (pw != null)
			this.password = new String(pw);
		else
			this.password = null;
		return ((this.account != null) && (!(this.account.matches("[\\s]*"))));
	}

	protected final byte[] encrypt(String srcData) {
		if (srcData == null)
			srcData = "";
		return encrypt(srcData.getBytes());
	}

	protected final byte[] encrypt(byte[] srcData) {
		byte[] enData = null;
		String alg = getPasswordAlgorithm();
		if (alg == null)
			enData = srcData;
		else if (alg.equalsIgnoreCase("DES-ARE"))
			enData = DESEncrypt.encrypt(srcData);
		else if (alg.equalsIgnoreCase("MD5-ARE")) {
			// enData = new MD5().getMD5ofBytes(new String(srcData));
		} else {
			try {
				MessageDigest md = MessageDigest.getInstance(alg);
				enData = md.digest(srcData);
			} catch (NoSuchAlgorithmException ex) {
				ARE.getLog().debug("Not support algorithm: " + alg, ex);
				enData = srcData;
			}
		}
		return enData;
	}

	public final String getEncryptString(String srcData) {
		if (srcData == null)
			return null;
		String enString = null;
		String alg = getPasswordAlgorithm();

		if (alg == null) {
			enString = srcData;
		} else if (alg.equalsIgnoreCase("DES-ARE")) {
			enString = DESEncrypt.encrypt(srcData);
		} else if (alg.equalsIgnoreCase("MD5-ARE")) {
			// enString = new MD5().getMD5ofStr(srcData);
		} else {
			byte[] d = encrypt(srcData);
			StringBuffer sb = new StringBuffer();
			for (int i = 0; i < d.length; ++i) {
				int t = d[i];
				sb.append(Integer.toString(t >> 4 & 0xF, 16)).append(
						Integer.toString(t & 0xF, 16));
			}

			enString = sb.toString();
		}

		return enString.toUpperCase();
	}

	public int getMaxRetryTimes() {
		return this.maxRetryTimes;
	}

	public void setMaxRetryTimes(int maxRetryTimes) {
		this.maxRetryTimes = maxRetryTimes;
	}

	public String getAccountPrompt() {
		return this.accountPrompt;
	}

	public void setAccountPrompt(String accountPrompt) {
		this.accountPrompt = accountPrompt;
	}

	public String getPasswordPrompt() {
		return this.passwordPrompt;
	}

	public void setPasswordPrompt(String passwordPrompt) {
		this.passwordPrompt = passwordPrompt;
	}

	public String getPasswordAlgorithm() {
		return this.passwordAlgorithm;
	}

	public void setPasswordAlgorithm(String passwordAlgorithm) {
		this.passwordAlgorithm = passwordAlgorithm;
	}
}